home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / WINER.ZIP / TEXTFIND.BAS < prev    next >
BASIC Source File  |  1994-09-04  |  7KB  |  201 lines

  1. '*********** TEXTFIND.BAS - finds text in a group of files
  2.  
  3. 'Copyright (c) 1992 by Ethan Winer
  4.  
  5. 'If you are using QBX version 7.1 beware of a nasty bug: After running this
  6. 'program QBX will hang if you cut and then paste any text.  To prove the bug
  7. 'is in QBX and not in this program, do the following:
  8. '
  9. '  1. Load this program and QBX.QLB using QBX TEXTFIND /L.
  10. '  2. Press F10 once to Execute to the first DIM statement.
  11. '  3. Go to line 53 and delete the code FNMax% = Value1.
  12. '  4. Go to the end of the line above and press Enter.
  13. '  5. Press the space bar twice, and then press Ctrl-Insert.
  14. '  6. Press the down arrow key once and then Delete; QBX is now hung!
  15.  
  16. DEFINT A-Z
  17.  
  18. TYPE RegTypeX                   'used by CALL INTERRUPTX
  19.   AX    AS INTEGER
  20.   BX    AS INTEGER
  21.   CX    AS INTEGER
  22.   DX    AS INTEGER
  23.   BP    AS INTEGER
  24.   SI    AS INTEGER
  25.   DI    AS INTEGER
  26.   Flags AS INTEGER
  27.   DS    AS INTEGER
  28.   ES    AS INTEGER
  29. END TYPE
  30. DIM Registers AS RegTypeX       'holds the CPU registers
  31.  
  32. TYPE DTA                        'used by DOS services
  33.   Reserved  AS STRING * 21      'reserved for use by DOS
  34.   Attribute AS STRING * 1       'the file's attribute
  35.   FileTime  AS STRING * 2       'the file's time
  36.   FileDate  AS STRING * 2       'the file's date
  37.   FileSize  AS LONG             'the file's size
  38.   FileName  AS STRING * 13      'the file's name
  39. END TYPE
  40. DIM DTAData AS DTA
  41.  
  42. DECLARE SUB InterruptX (IntNumber, InRegs AS RegTypeX, OutRegs AS RegTypeX)
  43.  
  44. CONST MaxFiles% = 1000
  45. CONST BufMax% = 4096
  46.  
  47. REDIM Array$(1 TO MaxFiles%)    'holds the file names
  48. Zero$ = CHR$(0)                 'do this once for speed
  49.  
  50. '----- This function returns the larger of two integers.
  51. DEF FNMax% (Value1, Value2)
  52.   FNMax% = Value1
  53.   IF Value2 > Value1 THEN FNMax% = Value2
  54. END DEF
  55.  
  56. '----- This function loads a group of file names.
  57. DEF FNLoadNames%
  58.  
  59.   STATIC Count
  60.  
  61.   '---- define a new Data Transfer Area for DOS
  62.   Registers.DX = VARPTR(DTAData)
  63.   Registers.DS = VARSEG(DTAData)
  64.   Registers.AX = &H1A00
  65.   CALL InterruptX(&H21, Registers, Registers)
  66.  
  67.   Count = 0                  'zero the file counter
  68.   Spec$ = Spec$ + Zero$      'DOS needs ASCIIZ strings
  69.   Registers.DX = SADD(Spec$) 'show where the spec is
  70.   Registers.DS = SSEG(Spec$)    'use this with PDS
  71.  'Registers.DS = VARSEG(Spec$)  'use this with QB
  72.   Registers.CX = 39          'the attribute for any file
  73.   Registers.AX = &H4E00      'find file name service
  74.  
  75.   '---- Read the file names that match the search
  76.   '     specification.  The Flags registers indicates
  77.   '     when no more matching files are found.  Copy
  78.   '     each file name to the string array.  Service
  79.   '     &H4F is used to continue the search started
  80.   '     with service &H4E using the same file spec.
  81.   DO
  82.     CALL InterruptX(&H21, Registers, Registers)
  83.     IF Registers.Flags AND 1 THEN EXIT DO
  84.     Count = Count + 1
  85.     Array$(Count) = DTAData.FileName
  86.     Registers.AX = &H4F00
  87.   LOOP WHILE Count < MaxFiles%
  88.  
  89.   FNLoadNames% = Count       'return the number of files
  90.  
  91. END DEF
  92.  
  93. '----- The main body of the program begins here.
  94. PRINT "TEXTFIND Copyright (c) 1991, Ziff-Davis Press."
  95. PRINT
  96.  
  97. '---- Get the file specification,or prompt for one
  98. '     if it wasn't given.
  99. Spec$ = COMMAND$
  100. IF LEN(Spec$) = 0 THEN
  101.   PRINT "Enter a file specification: ";
  102.   INPUT "", Spec$
  103. END IF
  104.  
  105. '----- Ask for the search string to find.
  106. PRINT "    Enter the text to find: ";
  107. INPUT Find$
  108. PRINT
  109.  
  110. Find$ = UCASE$(Find$)        'ignore capitalization
  111. FindLength = LEN(Find$)      'see how long Find$ is
  112. IF FindLength = 0 THEN END
  113.  
  114. Count = FNLoadNames%         'load the file names
  115. IF Count = 0 THEN
  116.   PRINT "No matching files"
  117.   END
  118. END IF
  119.  
  120. '----- Isolate the drive and path if given by searching
  121. '      for the ASCII values 58 and 92.
  122. FOR X = LEN(Spec$) TO 1 STEP -1
  123.   Char = ASC(MID$(Spec$, X))
  124.   IF Char = 58 OR Char = 92 THEN
  125.     Path$ = LEFT$(UCASE$(Spec$), X)
  126.     EXIT FOR
  127.   END IF
  128. NEXT
  129.  
  130. FOR X = 1 TO Count           'for each matching file
  131.   Array$(X) = LEFT$(Array$(X), INSTR(Array$(X), Zero$) - 1)
  132.   PRINT "Reading "; Path$; Array$(X)
  133.   OPEN Path$ + Array$(X) FOR BINARY AS #1
  134.   Length& = LOF(1)           'get and save its length
  135.   IF Length& < FindLength GOTO NextFile
  136.    
  137.   BufSize = BufMax%          'assume a 4K text buffer
  138.   IF BufSize > Length& THEN BufSize = Length&
  139.   Buffer$ = SPACE$(BufSize)  'create the file buffer
  140.  
  141.   LastSeek& = 1              'seed the SEEK location
  142.   BaseAddr& = 1              'and the starting offset
  143.   Bytes = 0                  'how many bytes to search
  144.  
  145.   DO                         'the file read loop
  146.      BaseAddr& = BaseAddr& + Bytes 'track block start
  147.      IF Length& - LastSeek& + 1 >= BufSize THEN
  148.        Bytes = BufSize       'at least BufSize bytes left
  149.      ELSE                    'get just what remains
  150.        Bytes = Length& - LastSeek& + 1
  151.        Buffer$ = SPACE$(Bytes) 'adjust the buffer size
  152.      END IF
  153.  
  154.      SEEK #1, LastSeek&      'seek back in the file
  155.      GET #1, , Buffer$       'read a chunk of the file
  156.  
  157.      Start = 1               'this is the INSTR loop for
  158.      DO                      'searching within the buffer
  159.        Found = INSTR(Start, UCASE$(Buffer$), Find$)
  160.        IF Found THEN         'print it in context
  161.          Start = Found + 1   'to resume using INSTR later
  162.          PRINT               'add a blank line for clarity
  163.          PRINT MID$(Buffer$, FNMax%(1, Found - 20), FindLength + 40)
  164.          PRINT
  165.            
  166.          PRINT "Continue searching "; Array$(X);
  167.          PRINT "? (Yes/No/Skip): ";
  168.          WHILE INKEY$ <> "": WEND   'clear kbrd buffer
  169.          DO
  170.            KeyHit$ = UCASE$(INKEY$) 'then get a response
  171.          LOOP UNTIL KeyHit$ = "Y" OR KeyHit$ = "N" OR KeyHit$ = "S"
  172.          PRINT KeyHit$              'echo the letter
  173.          PRINT
  174.  
  175.          IF KeyHit$ = "N" THEN      '"No"
  176.            END                      'end the program
  177.          ELSEIF KeyHit$ = "S" THEN  '"Skip"
  178.            GOTO NextFile            'go to the next file
  179.          END IF
  180.  
  181.        END IF
  182.                                     'search for multiple hits
  183.      LOOP WHILE Found               'within the file buffer
  184.  
  185.      IF Bytes = BufSize THEN        'still more file to examine
  186.        '---- Back up a bit in case Find$ is there but
  187.        '     straddling the buffer boundary.  Then update
  188.        '     the internal SEEK pointer.
  189.        BaseAddr& = BaseAddr& - FindLength
  190.        LastSeek& = BaseAddr& + Bytes
  191.      END IF
  192.  
  193.   LOOP WHILE Bytes = BufSize AND BufSize = BufMax%
  194.  
  195. NextFile:
  196.   CLOSE #1
  197.   Buffer$ = ""               'clear the buffer for later
  198.  
  199. NEXT
  200.  
  201.